﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Threading;
using System.Drawing.Imaging;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using System.Threading.Tasks;

namespace WebCam.Data.WebCamWorker.OneShotWebcamCore
{
    public class SimpleWebCam : ISimpleWebCam
    {
        const int interval = 1000 / 30;
        OneShot shot;
        Rectangle rect;
        //Bitmap oldImage = null;
        const int delta = 70;        

        public List<IWorker> Workers { get; set; }

        private object lockObject = new object();

        public void AddWorker(IWorker worker)
        {
            lock (lockObject)
            {
                if (worker == null)
                {
                    throw new ArgumentNullException("Worker is null");
                }
                Type type = worker.GetType();
                if (Workers.Count(p => p.GetType() == type) == 0)
                {
                    Workers.Add(worker);
                }
                else
                {
                    LogEntry entry = new LogEntry();
                    entry.Message = "Worker \"" + type.ToString() + "\" already exist in AddWorkers method";
                    Logger.Write(entry);
                }
            }
        }

        public void RemoveWorker(Type workerType)
        {
            lock (lockObject)
            {
                var worker = Workers.FirstOrDefault(p => p.GetType() == workerType);
                if (worker != null)
                {
                    Workers.Remove(worker);
                }
                else
                {
                    LogEntry entry = new LogEntry();
                    entry.Message = "Worker \"" + workerType.ToString() + "\" not exist in Workers list";
                    Logger.Write(entry);
                }
            }
        }

        public SimpleWebCam(IWorker startWorker)
        {
            Workers = new List<IWorker>();
            AddWorker(startWorker);
            rect = new Rectangle(0, 0, Width, Height);
        }

        DispatcherTimer timer = new DispatcherTimer();
        public void Start()
        {
            if (shot != null)
            {
                shot.stopCam();
            }
            shot = new OneShot();
            shot.InitcamNew();

            timer.Interval = new TimeSpan(0, 0, 0, 0, interval);
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();
        }        

        void timer_Tick(object sender, EventArgs e)
        {
            shot.UpdateImage();
            Bitmap image = shot.AcurrShot;

            lock (lockObject)
            {
                for (int i = 0; i < Workers.Count; i++ )
                {
                    Workers[i].ProcessBitmap(image);
                }
            }

            //BitmapData imageData = image.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            //unsafe
            //{
                //byte* pImage = (byte*)imageData.Scan0.ToPointer();
                //Task[] taskList = new Task[Workers.Count];
                //for(int i = 0 ; i < Workers.Count ; i++)
                //{
                    //taskList[i] = Task.Factory.StartNew(() => Workers[i].ProcessBitmap(pImage));
                //}
                //Task.WaitAll(taskList, 1000);
            //}
//            GetImage();
        }

        //protected void GetImage()
        //{
        //    shot.UpdateImage();
        //    Bitmap image = shot.AcurrShot;

        //    if (oldImage == null)
        //    {
        //        oldImage = image;
        //        return;
        //    }

        //    Bitmap tmp = (Bitmap)image.Clone();

        //    BitmapData imageData = image.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        //    BitmapData oldImageData = oldImage.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        //    BitmapData tmpData = tmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

        //    unsafe
        //    {
        //        byte* pImage = (byte*)imageData.Scan0.ToPointer();
        //        byte* pOldImage = (byte*)oldImageData.Scan0.ToPointer();
        //        byte* pTmpImage = (byte*)tmpData.Scan0.ToPointer();

        //        //int index = 0;
        //        for (int i = 0; i < Width; i++)
        //        {
        //            for (int j = 0; j < Height; j++)
        //            {
        //                byte r = *pImage;
        //                byte g = *(pImage + 1);
        //                byte b = *(pImage + 2);

        //                byte or = *(pOldImage);
        //                byte og = *(pOldImage + 1);
        //                byte ob = *(pOldImage + 2);

        //                //if (Math.Abs(r - or) + Math.Abs(g - og) + Math.Abs(b - ob) < 150)
        //                if (Math.Abs(r - or) > delta || Math.Abs(g - og) > delta || Math.Abs(b - ob) > delta)
        //                {
        //                    *pTmpImage = 0;
        //                    *(pTmpImage + 1) = 0;
        //                    *(pTmpImage + 2) = 255;
        //                }

        //                pImage += 3;
        //                pOldImage += 3;
        //                pTmpImage += 3;
        //                //index++;
        //            }
        //        }
        //    }

        //    image.UnlockBits(imageData);
        //    oldImage.UnlockBits(oldImageData);
        //    tmp.UnlockBits(tmpData);

        //    oldImage = image;

        //    if (OnBitmapLoaded != null)
        //    {
        //        lock (lock_Obj)
        //        {
        //            //Bitmap bmp = GetImage();
        //            if (OnBitmapLoaded != null)
        //            {
        //                OnBitmapLoaded(tmp);
        //            }
        //        }
        //    }
        //}

        public void Stop()
        {
            timer.Stop();
            shot.stopCam();
        }

        public int Width
        {
            get { return 640; }
        }

        public int Height
        {
            get { return 480; }
        }

        public double FPS
        {
            get { return interval; }
        }
    }
}
